#include <bsl_err_internal.h>
#include <bsl_errno.h>
#include <bsl_params.h>
#include <bsl_sal.h>
#include <crypt_algid.h>
#include <crypt_eal_md.h>
#include <crypt_errno.h>
#include <crypt_rsa.h>
#include <crypt_utils.h>
#include <securec.h>

#include <wd.h>
#include <wd_bmm.h>
#include <wd_rsa.h>

#include "kaev1_rsa.h"
#include "kaev1_rsa_local.h"
#include "kaep_err.h"
#include "kaev1_memory.h"

#define RSA_BLOCK_NUM  16
#define RSA_BLOCK_SIZE 4096

KaeQueuePoolHead *gRsaNodePool = NULL;

int WdRsaInitQnodePool(void)
{
    KaeQueuePoolDestroy(gRsaNodePool);

    gRsaNodePool = KaeInitQueuePool(WCRYPTO_RSA);
    if (gRsaNodePool == NULL) {
        return KAE_WD_DO_DIGEST_FAIL;
    }
    return CRYPT_SUCCESS;
}

int WdRsaDestroyQnodePool(void)
{
    KaeQueuePoolDestroy(gRsaNodePool);
    return CRYPT_SUCCESS;
}

static void HpreRsaCallback(const void *message, void *tag)
{
    if (!message || !tag) {
        return;
    }
    struct wcrypto_rsa_msg *msg = (struct wcrypto_rsa_msg *)message;
    KAE_RSA_Ctx *ctx = (KAE_RSA_Ctx *)tag;
    ctx->opData.out = msg->out;
    ctx->opData.out_bytes = msg->out_bytes;
    ctx->opData.status = msg->result;
}

void KAE_RSA_Free(KAE_RSA_Ctx *ctx)
{
    if (ctx == NULL) {
        return;
    }

    KAE_RSA_FreePara(ctx->para);
    ctx->para = NULL;

    if (ctx->rsaCtx) {
        wcrypto_del_rsa_ctx(ctx->rsaCtx);
        ctx->rsaCtx = NULL;
    }

    if (ctx->pool && ctx->opData.in) {
        wd_free_blk(ctx->pool, ctx->opData.in);
        ctx->opData.in = NULL;
    }

    if (ctx->pool && ctx->opData.out) {
        wd_free_blk(ctx->pool, ctx->opData.out);
        ctx->opData.out = NULL;
    }

    KaePutNodeToPool(gRsaNodePool, ctx->entry);

    KAE_RSA_FreePubKey(ctx->kPubKey);
    ctx->kPubKey = NULL;
    KAE_RSA_FreePrvKey(ctx->kPrvKey);
    ctx->kPrvKey = NULL;
    BSL_SAL_CleanseData((void *)(&(ctx->pad)), sizeof(RSAPad));
    BSL_SAL_FREE(ctx->label.data);

    free(ctx);
    ctx = NULL;
}

RSA_Para *KAE_RSA_NewParaFromBits(uint32_t bits)
{
    RSA_Para *newPara = (RSA_Para *)malloc(sizeof(RSA_Para));

    newPara->e = BN_Create(bits);
    newPara->p = BN_Create(bits);
    newPara->q = BN_Create(bits);

    if (newPara == NULL || newPara->e == NULL || newPara->p == NULL) {
        KAE_RSA_FreePara(newPara);
        newPara = NULL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }

    newPara->bits = bits;
    return newPara;
}

int32_t KAE_RSA_ParaCopy(RSA_Para *dst, RSA_Para *src)
{
    if (dst == NULL || src == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    dst->bits = src->bits;
    int32_t ret;
    GOTO_ERR_IF(BN_Copy(dst->e, src->e), ret);
    GOTO_ERR_IF(BN_Copy(dst->p, src->p), ret);
    GOTO_ERR_IF(BN_Copy(dst->q, src->q), ret);
ERR:
    return ret;
}

KAE_RSA_Ctx *KAE_RSA_NewCtx()
{
    KAE_RSA_Ctx *ctx = (KAE_RSA_Ctx *)malloc(sizeof(KAE_RSA_Ctx));
    if (ctx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }

    memset(ctx, 0, sizeof(KAE_RSA_Ctx));

    ctx->entry = KaeGetNodeFromPool(gRsaNodePool);
    if (ctx->entry == NULL) {
        KAE_RSA_Free(ctx);
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }

    ctx->queue = ctx->entry->queue;
    ctx->pool = ctx->entry->mempool;

    ctx->setup.cb = (wcrypto_cb)HpreRsaCallback;
    ctx->setup.is_crt = 0;
    ctx->setup.br.alloc = (void *)wd_alloc_blk;
    ctx->setup.br.free = (void *)wd_free_blk;
    ctx->setup.br.iova_map = (void *)wd_blk_iova_map;
    ctx->setup.br.iova_unmap = (void *)wd_blk_iova_unmap;
    ctx->setup.br.usr = ctx->pool;
    return ctx;
}

int32_t KAE_RSA_StoreOut(KAE_RSA_Ctx *ctx)
{
    struct wd_dtb wd_d;
    struct wd_dtb wd_n;
    struct wd_dtb wd_qinv;
    struct wd_dtb wd_dq;
    struct wd_dtb wd_dp;

    struct wcrypto_rsa_kg_out *out = (struct wcrypto_rsa_kg_out *)ctx->opData.out;
    wcrypto_get_rsa_kg_out_params(out, &wd_d, &wd_n);
    wcrypto_get_rsa_kg_out_crt_params(out, &wd_qinv, &wd_dq, &wd_dp);

    int32_t ret;
    int keySize = BN_BITS_TO_BYTES(ctx->para->bits);
    GOTO_ERR_IF(BN_Bin2Bn(ctx->kPrvKey->n, wd_n.data, keySize), ret);
    GOTO_ERR_IF(BN_Bin2Bn(ctx->kPrvKey->d, wd_d.data, keySize), ret);
    GOTO_ERR_IF(BN_Bin2Bn(ctx->kPrvKey->qInv, wd_qinv.data, wd_qinv.dsize), ret);
    GOTO_ERR_IF(BN_Bin2Bn(ctx->kPrvKey->dP, wd_dp.data, wd_dp.dsize), ret);
    GOTO_ERR_IF(BN_Bin2Bn(ctx->kPrvKey->dQ, wd_dq.data, wd_dq.dsize), ret);
ERR:
    return ret;
}

RSA_Para *KAE_RSA_DupPara(const RSA_Para *para)
{
    RSA_Para *paraCopy = (RSA_Para *)malloc(sizeof(RSA_Para));
    if (paraCopy == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }
    paraCopy->bits = para->bits;
    paraCopy->e = BN_Dup(para->e);
    paraCopy->p = BN_Dup(para->p);
    paraCopy->q = BN_Dup(para->q);
    if (paraCopy->e == NULL || paraCopy->p == NULL || paraCopy->q == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        KAE_RSA_FreePara(paraCopy);
        paraCopy = NULL;
        return NULL;
    }
    return paraCopy;
}

static KAE_RSA_PubKey *RSAPubKeyDupCtx(KAE_RSA_PubKey *pubKey)
{
    KAE_RSA_PubKey *newPubKey = (KAE_RSA_PubKey *)malloc(sizeof(KAE_RSA_PubKey));
    if (newPubKey == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }

    (void)memset_s(newPubKey, sizeof(KAE_RSA_PubKey), 0, sizeof(KAE_RSA_PubKey));

    GOTO_ERR_IF_SRC_NOT_NULL(newPubKey->e, pubKey->e, BN_Dup(pubKey->e), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPubKey->n, pubKey->n, BN_Dup(pubKey->n), CRYPT_MEM_ALLOC_FAIL);

    newPubKey->mont = BN_MontCreate(pubKey->n);
    if (newPubKey->mont == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }

    return newPubKey;

ERR:
    KAE_RSA_FreePubKey(newPubKey);
    newPubKey = NULL;
    return NULL;
}

static KAE_RSA_PrvKey *RSAPriKeyDupCtx(KAE_RSA_PrvKey *prvKey)
{
    KAE_RSA_PrvKey *newPriKey = (KAE_RSA_PrvKey *)malloc(sizeof(KAE_RSA_PrvKey));
    if (newPriKey == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }

    (void)memset_s(newPriKey, sizeof(KAE_RSA_PrvKey), 0, sizeof(KAE_RSA_PrvKey));

    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->n, prvKey->n, BN_Dup(prvKey->n), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->d, prvKey->d, BN_Dup(prvKey->d), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->p, prvKey->p, BN_Dup(prvKey->p), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->q, prvKey->q, BN_Dup(prvKey->q), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->dP, prvKey->dP, BN_Dup(prvKey->dP), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->dQ, prvKey->dQ, BN_Dup(prvKey->dQ), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->qInv, prvKey->qInv, BN_Dup(prvKey->qInv), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newPriKey->e, prvKey->e, BN_Dup(prvKey->e), CRYPT_MEM_ALLOC_FAIL);

    return newPriKey;
ERR:
    KAE_RSA_FreePrvKey(newPriKey);
    newPriKey = NULL;
    return NULL;
}

KAE_RSA_Ctx *KAE_RSA_DupCtx(KAE_RSA_Ctx *ctx)
{
    if (ctx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return NULL;
    }

    KAE_RSA_Ctx *newCtx = KAE_RSA_NewCtx();
    if (newCtx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return NULL;
    }

    int32_t ret;
    GOTO_ERR_IF_SRC_NOT_NULL(newCtx->para, ctx->para, KAE_RSA_DupPara(ctx->para), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newCtx->kPrvKey, ctx->kPrvKey, RSAPriKeyDupCtx(ctx->kPrvKey), CRYPT_MEM_ALLOC_FAIL);
    GOTO_ERR_IF_SRC_NOT_NULL(newCtx->kPubKey, ctx->kPubKey, RSAPubKeyDupCtx(ctx->kPubKey), CRYPT_MEM_ALLOC_FAIL);
    newCtx->flags = ctx->flags;
    (void)memcpy_s(&(newCtx->pad), sizeof(RSAPad), &(ctx->pad), sizeof(RSAPad));
    newCtx->setup.key_bits = ctx->setup.key_bits;
    newCtx->setup.is_crt = ctx->setup.is_crt;
    return newCtx;
ERR:
    KAE_RSA_Free(newCtx);
    return NULL;
}

int32_t KAE_RSA_Cmp(const KAE_RSA_Ctx *a, const KAE_RSA_Ctx *b)
{
    RETURN_RET_IF(a == NULL || b == NULL, CRYPT_NULL_INPUT);

    RETURN_RET_IF(a->kPubKey == NULL || b->kPubKey == NULL, CRYPT_RSA_NO_KEY_INFO);

    RETURN_RET_IF(BN_Cmp(a->kPubKey->n, b->kPubKey->n) != 0 || BN_Cmp(a->kPubKey->e, b->kPubKey->e) != 0,
                  CRYPT_RSA_PUBKEY_NOT_EQUAL);

    return CRYPT_SUCCESS;
}

int32_t Rsa_Fill_PubKey(KAE_RSA_Ctx *ctx)
{
    struct wd_dtb *wd_e = NULL;
    struct wd_dtb *wd_n = NULL;

    wcrypto_get_rsa_pubkey(ctx->rsaCtx, &ctx->pubKey);
    wcrypto_get_rsa_pubkey_params(ctx->pubKey, &wd_e, &wd_n);

    int32_t ret;
    uint32_t bnBytes = BN_Bytes(ctx->kPubKey->n);
    wd_n->dsize = bnBytes;
    wd_e->dsize = bnBytes;
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPubKey->n, (unsigned char *)wd_n->data, &(wd_n->dsize)), ret);
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPubKey->e, (unsigned char *)wd_e->data, &(wd_e->dsize)), ret);
ERR:
    return ret;
}

int32_t Rsa_Fill_PrvKeyNoCRT(KAE_RSA_Ctx *ctx)
{
    struct wd_dtb *wd_d = NULL;
    struct wd_dtb *wd_n = NULL;

    wcrypto_get_rsa_prikey(ctx->rsaCtx, &ctx->prvKey);
    wcrypto_get_rsa_prikey_params(ctx->prvKey, &wd_d, &wd_n);

    int32_t ret;
    uint32_t bnBytes = BN_Bytes(ctx->kPrvKey->n);
    wd_n->dsize = bnBytes;
    wd_d->dsize = bnBytes;
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->n, (unsigned char *)wd_n->data, &(wd_n->dsize)), ret);
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->d, (unsigned char *)wd_d->data, &(wd_d->dsize)), ret);
ERR:
    return ret;
}

int32_t Rsa_Fill_PrvKeyCRT(KAE_RSA_Ctx *ctx)
{
    struct wd_dtb *wd_dq;
    struct wd_dtb *wd_dp;
    struct wd_dtb *wd_q;
    struct wd_dtb *wd_p;
    struct wd_dtb *wd_qinv;

    wcrypto_get_rsa_prikey(ctx->rsaCtx, &ctx->prvKey);
    wcrypto_get_rsa_crt_prikey_params(ctx->prvKey, &wd_dq, &wd_dp, &wd_qinv, &wd_q, &wd_p);

    int32_t ret;
    uint32_t bnBytes = BN_Bytes(ctx->kPrvKey->n);
    wd_p->dsize = bnBytes;
    wd_q->dsize = bnBytes;
    wd_dp->dsize = bnBytes;
    wd_dq->dsize = bnBytes;
    wd_qinv->dsize = bnBytes;

    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->p, (unsigned char *)wd_p->data, &(wd_p->dsize)), ret);
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->q, (unsigned char *)wd_q->data, &(wd_q->dsize)), ret);
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->dP, (unsigned char *)wd_dp->data, &(wd_dp->dsize)), ret);
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->dQ, (unsigned char *)wd_dq->data, &(wd_dq->dsize)), ret);
    GOTO_ERR_IF(BN_Bn2Bin(ctx->kPrvKey->qInv, (unsigned char *)wd_qinv->data, &(wd_qinv->dsize)), ret);
ERR:
    return ret;
}

int32_t KAE_RSA_GenKey(KAE_RSA_Ctx *ctx)
{
    if (ctx == NULL || ctx->para == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (RSA_CheckBitsLength(ctx->para->bits) != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(KAE_WD_ERR_KEY_BITS);
        return KAE_WD_ERR_KEY_BITS;
    }

    int32_t ret = CRYPT_MEM_ALLOC_FAIL;
    KAE_RSA_Ctx *newCtx = KAE_RSA_NewCtx();
    if (newCtx == NULL) {
        BSL_ERR_PUSH_ERROR(ret);
        return ret;
    }

    newCtx->para = KAE_RSA_DupPara(ctx->para);
    if (newCtx->para == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }

    newCtx->kPrvKey = KAE_RSA_NewPrvKey(newCtx->para->bits);
    newCtx->kPubKey = KAE_RSA_NewPubKey(newCtx->para->bits);

    ret = KAE_RSA_Gen(newCtx);
    if (ret != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(ret);
        goto ERR;
    }

    newCtx->setup.key_bits = newCtx->para->bits;
    newCtx->setup.is_crt = 1;

    newCtx->rsaCtx = wcrypto_create_rsa_ctx(newCtx->queue, &newCtx->setup);
    if (newCtx->rsaCtx == NULL) {
        ret = KAE_WD_CREATE_CTX_FAIL;
        BSL_ERR_PUSH_ERROR(KAE_WD_CREATE_CTX_FAIL);
        goto ERR;
    };

    struct wd_dtb *wd_e = NULL;
    struct wd_dtb *wd_p = NULL;
    struct wd_dtb *wd_q = NULL;

    wcrypto_get_rsa_pubkey(newCtx->rsaCtx, &newCtx->pubKey);
    wcrypto_get_rsa_pubkey_params(newCtx->pubKey, &wd_e, NULL);
    wcrypto_get_rsa_prikey(newCtx->rsaCtx, &newCtx->prvKey);
    wcrypto_get_rsa_crt_prikey_params(newCtx->prvKey, NULL, NULL, NULL, &wd_q, &wd_p);

    uint32_t bnBytes = BN_BITS_TO_BYTES(newCtx->para->bits);

    wd_e->dsize = bnBytes;
    wd_p->dsize = bnBytes;
    wd_q->dsize = bnBytes;
    GOTO_ERR_IF(BN_Bn2Bin(newCtx->para->e, wd_e->data, &wd_e->dsize), ret);
    GOTO_ERR_IF(BN_Bn2Bin(newCtx->kPrvKey->p, wd_p->data, &wd_p->dsize), ret);
    GOTO_ERR_IF(BN_Bn2Bin(newCtx->kPrvKey->q, wd_q->data, &wd_q->dsize), ret);

    newCtx->opData.op_type = WCRYPTO_RSA_GENKEY;
    newCtx->opData.in_bytes = BN_BITS_TO_BYTES(newCtx->para->bits);
    newCtx->opData.in = wcrypto_new_kg_in(newCtx->rsaCtx, wd_e, wd_p, wd_q);
    if (newCtx->opData.in == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    newCtx->opData.out = wcrypto_new_kg_out(newCtx->rsaCtx);
    if (newCtx->opData.out == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    if (wcrypto_do_rsa(newCtx->rsaCtx, &newCtx->opData, NULL) != 0) {
        ret = KAE_WD_DO_RSA_FAIL;
        BSL_ERR_PUSH_ERROR(KAE_WD_DO_RSA_FAIL);
        goto ERR;
    }
    GOTO_ERR_IF(KAE_RSA_StoreOut(newCtx), ret);
    GOTO_ERR_IF(BN_Copy(newCtx->kPubKey->n, newCtx->kPrvKey->n), ret);
    GOTO_ERR_IF(BN_Copy(newCtx->kPubKey->e, newCtx->para->e), ret);
    GOTO_ERR_IF(BN_Copy(newCtx->kPrvKey->e, newCtx->para->e), ret);

    KAE_RSA_FreePrvKey(ctx->kPrvKey);
    KAE_RSA_FreePubKey(ctx->kPubKey);
    ctx->kPubKey = RSAPubKeyDupCtx(newCtx->kPubKey);
    ctx->kPrvKey = RSAPriKeyDupCtx(newCtx->kPrvKey);
    KAE_RSA_Free(newCtx);
    return ret;
ERR:
    KAE_RSA_Free(newCtx);
    return ret;
}

static uint32_t GetHashLen(const KAE_RSA_Ctx *ctx)
{
    if (ctx->pad.type == EMSA_PKCSV15) {
        return CRYPT_GetMdSizeById(ctx->pad.para.pkcsv15.mdId);
    }

    return (uint32_t)(ctx->pad.para.pss.mdMeth->mdSize);
}

int32_t KAE_RSA_SignData(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *sign, uint32_t *signLen)
{
    if (ctx == NULL || (data == NULL && dataLen != 0) || sign == NULL || signLen == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (ctx->kPrvKey == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_NO_KEY_INFO);
        return CRYPT_RSA_NO_KEY_INFO;
    }

    uint32_t bits = KAE_RSA_GetBits(ctx);
    if ((*signLen) < BN_BITS_TO_BYTES(bits)) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_BUFF_LEN_NOT_ENOUGH);
        return CRYPT_RSA_BUFF_LEN_NOT_ENOUGH;
    }
    if (RSA_CheckBitsLength(bits) != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(KAE_WD_ERR_KEY_BITS);
        return KAE_WD_ERR_KEY_BITS;
    }
    if (ctx->pad.type != EMSA_PKCSV15 && ctx->pad.type != EMSA_PSS) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_PAD_NO_SET_ERROR);
        return CRYPT_RSA_PAD_NO_SET_ERROR;
    }

    if (GetHashLen(ctx) != dataLen) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_ERR_ALGID);
        return CRYPT_RSA_ERR_ALGID;
    }
    ctx->rsaCtx = wcrypto_create_rsa_ctx(ctx->queue, &ctx->setup);
    if (ctx->rsaCtx == NULL) {
        BSL_ERR_PUSH_ERROR(KAE_WD_CREATE_CTX_FAIL);
        return KAE_WD_CREATE_CTX_FAIL;
    };

    ctx->setup.is_crt ? Rsa_Fill_PrvKeyCRT(ctx) : Rsa_Fill_PrvKeyNoCRT(ctx);

    uint32_t padLen = BN_BITS_TO_BYTES(bits);
    uint8_t *pad = (uint8_t *)malloc(padLen);
    if (pad == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return CRYPT_MEM_ALLOC_FAIL;
    }
    int32_t ret;
    switch (ctx->pad.type) {
        case EMSA_PKCSV15:
            ret = CRYPT_RSA_SetPkcsV15Type1(ctx->pad.para.pkcsv15.mdId, data, dataLen, pad, padLen);
            break;
        case EMSA_PSS:
            ret = PssPad(ctx, data, dataLen, pad, padLen);
            break;
        default:
            ret = CRYPT_RSA_PAD_NO_SET_ERROR;
            BSL_ERR_PUSH_ERROR(ret);
            goto ERR;
    }

    ctx->opData.in_bytes = BN_BITS_TO_BYTES(bits);
    ctx->opData.op_type = WCRYPTO_RSA_SIGN;
    ctx->opData.in = wd_alloc_blk(ctx->pool);
    if (ctx->opData.in == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    ctx->opData.out = wd_alloc_blk(ctx->pool);
    if (ctx->opData.out == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    memcpy(ctx->opData.in, pad, ctx->opData.in_bytes);
    if (wcrypto_do_rsa(ctx->rsaCtx, &ctx->opData, NULL) != 0) {
        ret = KAE_WD_DO_RSA_FAIL;
        BSL_ERR_PUSH_ERROR(KAE_WD_DO_RSA_FAIL);
        goto ERR;
    }
    memcpy(sign, ctx->opData.out, ctx->opData.out_bytes);
    *signLen = ctx->opData.out_bytes;
ERR:
    (void)memset_s(pad, padLen, 0, padLen);
    BSL_SAL_FREE(pad);
    if (ctx->pool && ctx->opData.in) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.in);
        ctx->opData.in = NULL;
    }
    if (ctx->pool && ctx->opData.out) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.out);
        ctx->opData.out = NULL;
    }
    if (ctx->rsaCtx) {
        wcrypto_del_rsa_ctx(ctx->rsaCtx);
        ctx->rsaCtx = NULL;
    }
    return ret;
}

int32_t KAE_RSA_VerifyData(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *sign, uint32_t signLen)
{
    if (ctx == NULL || (data == NULL && dataLen != 0) || sign == NULL || signLen == 0) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (ctx->kPubKey == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_NO_KEY_INFO);
        return CRYPT_RSA_NO_KEY_INFO;
    }

    if (ctx->pad.type != EMSA_PKCSV15 && ctx->pad.type != EMSA_PSS) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_PAD_NO_SET_ERROR);
        return CRYPT_RSA_PAD_NO_SET_ERROR;
    }

    if (GetHashLen(ctx) != dataLen) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_ERR_ALGID);
        return CRYPT_RSA_ERR_ALGID;
    }

    uint32_t bits = KAE_RSA_GetBits(ctx);
    if (RSA_CheckBitsLength(bits) != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(KAE_WD_ERR_KEY_BITS);
        return KAE_WD_ERR_KEY_BITS;
    }

    int32_t ret;
    uint32_t padLen = BN_BITS_TO_BYTES(bits);
    uint8_t *pad = (uint8_t *)malloc(padLen);
    if (pad == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return CRYPT_MEM_ALLOC_FAIL;
    }

    ctx->rsaCtx = wcrypto_create_rsa_ctx(ctx->queue, &ctx->setup);
    if (ctx->rsaCtx == NULL) {
        BSL_ERR_PUSH_ERROR(KAE_WD_CREATE_CTX_FAIL);
        return KAE_WD_CREATE_CTX_FAIL;
    };
    uint8_t out[BN_BITS_TO_BYTES(bits)];
    Rsa_Fill_PubKey(ctx);
    ctx->opData.in_bytes = BN_BITS_TO_BYTES(bits);
    ctx->opData.op_type = WCRYPTO_RSA_VERIFY;
    ctx->opData.in = wd_alloc_blk(ctx->pool);
    if (ctx->opData.in == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    ctx->opData.out = wd_alloc_blk(ctx->pool);
    if (ctx->opData.out == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    memcpy(ctx->opData.in, sign, ctx->opData.in_bytes);
    if (wcrypto_do_rsa(ctx->rsaCtx, &ctx->opData, NULL) != 0) {
        ret = KAE_WD_DO_RSA_FAIL;
        BSL_ERR_PUSH_ERROR(KAE_WD_DO_RSA_FAIL);
        goto ERR;
    }
    memcpy(pad, ctx->opData.out, ctx->opData.out_bytes);
    padLen = ctx->opData.out_bytes;

    uint32_t saltLen = (uint32_t)ctx->pad.para.pss.saltLen;
    switch (ctx->pad.type) {
        case EMSA_PKCSV15:
            ret = CRYPT_RSA_VerifyPkcsV15Type1(ctx->pad.para.pkcsv15.mdId, pad, padLen, data, dataLen);
            break;
        case EMSA_PSS:
            if (ctx->pad.para.pss.saltLen == CRYPT_RSA_SALTLEN_TYPE_HASHLEN) { // saltLen is -1
                saltLen = (uint32_t)ctx->pad.para.pss.mdMeth->mdSize;
            } else if (ctx->pad.para.pss.saltLen == CRYPT_RSA_SALTLEN_TYPE_MAXLEN) { // saltLen is -2
                saltLen = (uint32_t)(padLen - ctx->pad.para.pss.mdMeth->mdSize - 2); // salt, obtains DRBG
            }
            ret = CRYPT_RSA_VerifyPss(ctx->pad.para.pss.mdMeth, ctx->pad.para.pss.mgfMeth, KAE_RSA_GetBits(ctx),
                                      saltLen, data, dataLen, pad, padLen);
            break;
        default: // This branch cannot be entered because it's been verified before.
            ret = CRYPT_RSA_PAD_NO_SET_ERROR;
            BSL_ERR_PUSH_ERROR(ret);
            goto ERR;
    }
ERR:
    (void)memset_s(pad, padLen, 0, padLen);
    BSL_SAL_FREE(pad);
    if (ctx->pool && ctx->opData.in) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.in);
        ctx->opData.in = NULL;
    }
    if (ctx->pool && ctx->opData.out) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.out);
        ctx->opData.out = NULL;
    }
    if (ctx->rsaCtx) {
        wcrypto_del_rsa_ctx(ctx->rsaCtx);
        ctx->rsaCtx = NULL;
    }
    return ret;
}

int32_t KAE_RSA_Encrypt(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *out, uint32_t *outLen)
{
    if (ctx == NULL || (data == NULL && dataLen != 0) || out == NULL || outLen == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (ctx->kPubKey == NULL) {
        // Check whether the public key information exists.
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_NO_KEY_INFO);
        return CRYPT_RSA_NO_KEY_INFO;
    }

    // Check whether the length of the out is sufficient to place the encryption information.
    uint32_t bits = KAE_RSA_GetBits(ctx);
    if ((*outLen) < BN_BITS_TO_BYTES(bits)) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_BUFF_LEN_NOT_ENOUGH);
        return CRYPT_RSA_BUFF_LEN_NOT_ENOUGH;
    }
    if (dataLen > BN_BITS_TO_BYTES(bits)) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_ERR_ENC_BITS);
        return CRYPT_RSA_ERR_ENC_BITS;
    }
    if (RSA_CheckBitsLength(bits) != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(KAE_WD_ERR_KEY_BITS);
        return KAE_WD_ERR_KEY_BITS;
    }

    int32_t ret = CRYPT_SUCCESS;
    uint32_t padLen = BN_BITS_TO_BYTES(bits);
    uint8_t *pad = (uint8_t *)malloc(padLen);
    if (pad == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return CRYPT_MEM_ALLOC_FAIL;
    }

    switch (ctx->pad.type) {
        case RSAES_PKCSV15_TLS:
        case RSAES_PKCSV15:
            ret = CRYPT_RSA_SetPkcsV15Type2(NULL, data, dataLen, pad, padLen);
            if (ret != CRYPT_SUCCESS) {
                BSL_ERR_PUSH_ERROR(ret);
                goto ERR;
            }
            break;
        case RSAES_OAEP:
            ret = RSA_SetPkcs1Oaep(ctx, data, dataLen, pad, padLen);
            if (ret != CRYPT_SUCCESS) {
                BSL_ERR_PUSH_ERROR(ret);
                goto ERR;
            }
            break;
        case RSA_NO_PAD:
            if (dataLen != padLen) {
                ret = CRYPT_RSA_ERR_ENC_INPUT_NOT_ENOUGH;
                BSL_ERR_PUSH_ERROR(CRYPT_RSA_ERR_ENC_INPUT_NOT_ENOUGH);
                goto ERR;
            }
            (void)memcpy_s(pad, padLen, data, dataLen);
            break;
        default:
            ret = CRYPT_RSA_PAD_NO_SET_ERROR;
            BSL_ERR_PUSH_ERROR(ret);
            goto ERR;
    }

    ctx->rsaCtx = wcrypto_create_rsa_ctx(ctx->queue, &ctx->setup);
    if (ctx->rsaCtx == NULL) {
        BSL_ERR_PUSH_ERROR(KAE_WD_CREATE_CTX_FAIL);
        return KAE_WD_CREATE_CTX_FAIL;
    };
    Rsa_Fill_PubKey(ctx);
    ctx->opData.in_bytes = BN_BITS_TO_BYTES(bits);
    ctx->opData.op_type = WCRYPTO_RSA_VERIFY;
    ctx->opData.in = wd_alloc_blk(ctx->pool);
    if (ctx->opData.in == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    ctx->opData.out = wd_alloc_blk(ctx->pool);
    if (ctx->opData.out == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    memcpy(ctx->opData.in, pad, ctx->opData.in_bytes);
    if (wcrypto_do_rsa(ctx->rsaCtx, &ctx->opData, NULL) != 0) {
        ret = KAE_WD_DO_RSA_FAIL;
        BSL_ERR_PUSH_ERROR(KAE_WD_DO_RSA_FAIL);
        goto ERR;
    }
    memcpy(out, ctx->opData.out, ctx->opData.out_bytes);
    *outLen = ctx->opData.out_bytes;
ERR:
    (void)memset_s(pad, padLen, 0, padLen);
    BSL_SAL_FREE(pad);
    if (ctx->pool && ctx->opData.in) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.in);
        ctx->opData.in = NULL;
    }
    if (ctx->pool && ctx->opData.out) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.out);
        ctx->opData.out = NULL;
    }
    if (ctx->rsaCtx) {
        wcrypto_del_rsa_ctx(ctx->rsaCtx);
        ctx->rsaCtx = NULL;
    }
    return ret;
}

int32_t KAE_RSA_Decrypt(KAE_RSA_Ctx *ctx, const uint8_t *data, uint32_t dataLen, uint8_t *out, uint32_t *outLen)
{
    if (ctx == NULL || data == NULL || out == NULL || outLen == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (ctx->kPrvKey == NULL) {
        // Check whether the private key information exists.
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_NO_KEY_INFO);
        return CRYPT_RSA_NO_KEY_INFO;
    }
    uint32_t bits = KAE_RSA_GetBits(ctx);
    if (dataLen != BN_BITS_TO_BYTES(bits)) {
        BSL_ERR_PUSH_ERROR(CRYPT_RSA_ERR_DEC_BITS);
        return CRYPT_RSA_ERR_DEC_BITS;
    }
    if (RSA_CheckBitsLength(bits) != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(KAE_WD_ERR_KEY_BITS);
        return KAE_WD_ERR_KEY_BITS;
    }

    int32_t ret = CRYPT_SUCCESS;
    ctx->rsaCtx = wcrypto_create_rsa_ctx(ctx->queue, &ctx->setup);
    if (ctx->rsaCtx == NULL) {
        BSL_ERR_PUSH_ERROR(KAE_WD_CREATE_CTX_FAIL);
        return KAE_WD_CREATE_CTX_FAIL;
    };

    ctx->setup.is_crt ? Rsa_Fill_PrvKeyCRT(ctx) : Rsa_Fill_PrvKeyNoCRT(ctx);

    ctx->opData.in_bytes = BN_BITS_TO_BYTES(bits);
    ctx->opData.op_type = WCRYPTO_RSA_SIGN;
    ctx->opData.in = wd_alloc_blk(ctx->pool);
    if (ctx->opData.in == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    ctx->opData.out = wd_alloc_blk(ctx->pool);
    if (ctx->opData.out == NULL) {
        ret = CRYPT_MEM_ALLOC_FAIL;
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        goto ERR;
    }
    memcpy(ctx->opData.in, data, ctx->opData.in_bytes);
    if (wcrypto_do_rsa(ctx->rsaCtx, &ctx->opData, NULL) != 0) {
        ret = KAE_WD_DO_RSA_FAIL;
        BSL_ERR_PUSH_ERROR(KAE_WD_DO_RSA_FAIL);
        goto ERR;
    }

    uint32_t padLen = BN_BITS_TO_BYTES(bits);
    uint8_t *pad = (uint8_t *)malloc(padLen);
    if (pad == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
        return CRYPT_MEM_ALLOC_FAIL;
    }

    (void)memcpy_s(pad, padLen, ctx->opData.out, ctx->opData.out_bytes);
    padLen = ctx->opData.out_bytes;
    switch (ctx->pad.type) {
        case RSAES_OAEP:
            ret = CRYPT_RSA_VerifyPkcs1Oaep(ctx->pad.para.oaep.mdMeth, ctx->pad.para.oaep.mgfMeth, pad, padLen,
                                            ctx->label.data, ctx->label.len, out, outLen);
            break;
        case RSAES_PKCSV15:
            ret = CRYPT_RSA_VerifyPkcsV15Type2(pad, padLen, out, outLen);
            break;
        case RSAES_PKCSV15_TLS:
            ret = CRYPT_RSA_VerifyPkcsV15Type2TLS(pad, padLen, out, outLen);
            break;
        case RSA_NO_PAD:
            if (memcpy_s(out, *outLen, pad, padLen) != EOK) {
                ret = CRYPT_RSA_BUFF_LEN_NOT_ENOUGH;
                BSL_ERR_PUSH_ERROR(CRYPT_RSA_BUFF_LEN_NOT_ENOUGH);
                goto ERR;
            }
            *outLen = padLen;
            break;
        default:
            ret = CRYPT_RSA_PAD_NO_SET_ERROR;
            BSL_ERR_PUSH_ERROR(ret);
            goto ERR;
    }
ERR:
    (void)memset_s(pad, padLen, 0, padLen);
    BSL_SAL_FREE(pad);
    if (ctx->pool && ctx->opData.in) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.in);
        ctx->opData.in = NULL;
    }
    if (ctx->pool && ctx->opData.out) {
        ctx->setup.br.free(ctx->setup.br.usr, ctx->opData.out);
        ctx->opData.out = NULL;
    }
    if (ctx->rsaCtx) {
        wcrypto_del_rsa_ctx(ctx->rsaCtx);
        ctx->rsaCtx = NULL;
    }
    return ret;
}

int32_t KAE_RSA_Sign(KAE_RSA_Ctx *ctx, int32_t algId, const uint8_t *data, uint32_t dataLen, uint8_t *sign,
                     uint32_t *signLen)
{
    uint8_t hash[64];
    uint32_t hashLen = sizeof(hash) / sizeof(hash[0]);
    int32_t ret = CRYPT_EAL_Md(algId, data, dataLen, hash, &hashLen);
    if (ret != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(ret);
        return ret;
    }
    return KAE_RSA_SignData(ctx, hash, hashLen, sign, signLen);
}

int32_t KAE_RSA_Verify(KAE_RSA_Ctx *ctx, int32_t algId, const uint8_t *data, uint32_t dataLen, uint8_t *sign,
                       uint32_t signLen)
{
    uint8_t hash[64];
    uint32_t hashLen = sizeof(hash) / sizeof(hash[0]);
    int32_t ret = CRYPT_EAL_Md(algId, data, dataLen, hash, &hashLen);
    if (ret != CRYPT_SUCCESS) {
        BSL_ERR_PUSH_ERROR(ret);
        return ret;
    }
    return KAE_RSA_VerifyData(ctx, hash, hashLen, sign, signLen);
}

int32_t KAE_RSA_Blind(KAE_RSA_Ctx *ctx, int32_t algId, const uint8_t *input, uint32_t inputLen, uint8_t *out,
                      uint32_t *outLen)
{
    if (ctx == NULL || input == NULL || inputLen == 0 || out == NULL || outLen == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    return KAE_WD_NOT_SUPPORT;
}

int32_t KAE_RSA_UnBlind(const KAE_RSA_Ctx *ctx, const uint8_t *input, uint32_t inputLen, uint8_t *out, uint32_t *outLen)
{
    if (ctx == NULL || input == NULL || inputLen == 0 || out == NULL || outLen == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    return KAE_WD_NOT_SUPPORT;
}